package servers;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

import org.apache.commons.codec.binary.Base64;
import org.grlea.log.SimpleLogger;

import vo.yahoo.ListMessageResponse;
import vo.yahoo.Message;
import vo.yahoo.MessageInfo;
import domainhandler.IDomainHandler;
import domainhandler.smtp.YahooBetaHandler;
import exception.LoginException;

//base implementation of RFC 821
public class SMTPService implements Runnable {

	private Socket socket;

	String username;

	Message message;
	StringBuilder sbRawMsg ;

	String password;

	private static final SimpleLogger log = new SimpleLogger(SMTPService.class);

	public void run() {
		log.entry("thread start");
		BufferedReader d = null;
		IDomainHandler domainHandler = null ;
		boolean dataReadIsON = false ;
		try {
			d = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			// As long as we receive data, echo that data back to the client.
			while (true) {
				String line = d.readLine();
				log.debugObject("line: ",line);
				
				// as long as data read is on dont do other requests
				if(dataReadIsON){
					if (getSbRawMsg() == null ) setSbRawMsg(new StringBuilder());
					getSbRawMsg().append(line);
					if(line.trim().equals(".") ){
						dataReadIsON = false;
						log.debugObject("final string", getSbRawMsg());
					}
					else continue;
				}
				
				if (line.toUpperCase().startsWith("EHLO")) {
					StringBuffer sbResp = new StringBuffer("");
					sbResp.append("250-PopAnyhting Offers following FIFTEEN extensions:\r\n");
					sbResp.append("250 AUTH plain\r\n");
//					sbResp.append("250-8BITMIME\r\n");
//					sbResp.append("250-PIPELINING\r\n");
//					sbResp.append("250-DSN\r\n");
//					sbResp.append("250-ENHANCEDSTATUSCODES\r\n");
//					sbResp.append("250-EXPN\r\n");
//					sbResp.append("250-HELP\r\n");
//					sbResp.append("250-SAML\r\n");
//					sbResp.append("250-SEND\r\n");
//					sbResp.append("250-SOML\r\n");
//					sbResp.append("250-TURN\r\n");
//					sbResp.append("250-XADR\r\n");
//					sbResp.append("250-XSTA\r\n");
//					sbResp.append("250-ETRN\r\n");
//					sbResp.append("250-XGEN\r\n");
//					sbResp.append("250 SIZE 51200000\r\n");
					bw.write(sbResp.toString());
					bw.flush();
				}
				else if (line.toUpperCase().startsWith("AUTH")) {
					String plainAuthString = new String(Base64.decodeBase64(line.split(" ")[2].getBytes()));
					log.debugObject("authString:", plainAuthString);
					
					// authString has username and password separated by \0
					String[] auth = plainAuthString.split("\0");
					
					String userId = auth[1].split("@")[0];
					setUsername(userId);
					setPassword(auth[2]);
					
					// TODO: have to write code to read the userid and domain by using auth[1].split("@")[0] and auth[1].split("@")[1]
					// right now hardcoded to Yahoo
					domainHandler = new YahooBetaHandler();
					
					// invoke the guy .. hardcoded to yahoo beta right now..
					domainHandler = new YahooBetaHandler();
					try {
						domainHandler.logIn(getUsername(),getPassword());
						bw.write("235 you are authenticated..\r\n");
					} catch (LoginException e) {
						e.printStackTrace();
						bw.write("550 Something is gone crazy..\r\n");
					}
					bw.flush();
				}
				else if (line.toUpperCase().startsWith("MAIL")) {
					if (getMessage() == null) setMessage(new Message());
					String fromEmail = line.split(" ")[1];
					message.setFromEmail(fromEmail.substring(6,fromEmail.length()-1));
					log.debugObject("fromEmail", getMessage());
					bw.write("250 Got the from address...\r\n");
					bw.flush();
				}
				else if (line.toUpperCase().startsWith("RCPT")) {
					// basically here we should be able to differenciate between which domain handled to invoke
					// so basic thing for me right now that i am not doing it.
					String toEmail = line.split(" ")[1];
					log.debugObject("to Email", toEmail);
					bw.write("250 OK\r\n");
					bw.flush();
				}
				else if (line.toUpperCase().startsWith("DATA")) {
					dataReadIsON = true ;
					bw.write("354 OK\r\n");
					bw.flush();
					
					/*ListMessageResponse resp = ((YahooBetaHandler)domainHandler).getListMessageResponse();
					if( resp == null ){
						// the data table is not yet downloaded
						((YahooBetaHandler)domainHandler).getStats();
						resp = ((YahooBetaHandler)domainHandler).getListMessageResponse();
					}else{
						StringBuffer sbResp = new StringBuffer("+OK ");
						sbResp.append(resp.getNoOfMessages()+" Messages\r\n");
						for (int i = 0 ; i < resp.getMessageList().size(); i++) {
							MessageInfo message = (MessageInfo) resp.getMessageList().get(i);
							sbResp.append(""+(i+1)+" "+message.getMid()+"\r\n");
						}
						sbResp.append(".\r\n");
						log.debug("UIDL response: "+sbResp);
						bw.write(sbResp.toString());
					}
					bw.flush();*/
				}
				else if (line.toUpperCase().startsWith("RETR")) {
				/*	String mId = line.split(" ")[1];
					log.debug("RETR message id: "+mId);
					StringBuffer sbResp = new StringBuffer("");
					StringBuffer message = ((YahooBetaHandler)domainHandler).getMessage(Integer.parseInt(mId));
					if( message == null ){
						sbResp.append("-ERR no data");
					}else{
						String paddedStr = message.toString().replace("[^\r]\n", "\r\n");
						paddedStr += "\r\n.\r\n";  //msg end
						sbResp.append("+OK "+paddedStr.length()+"\r\n");
						sbResp.append(paddedStr);
					}
					log.debug("RETR response: "+sbResp);
					bw.write(sbResp.toString());
					bw.flush();*/
				}
				else if (line.toUpperCase().startsWith("TOP")) {
					/*String mId = line.split(" ")[1];
					log.debug("TOP message id: "+mId);
					StringBuffer sbResp = new StringBuffer("");
					String message = ((YahooBetaHandler)domainHandler).getHeader(Integer.parseInt(mId));
					if( message == null ){
						sbResp.append("-ERR no data");
					}else{
						message += ".\r\n";  //msg end
						sbResp.append("+OK "+message.length()+"\r\n");
						sbResp.append(message);
					}
					log.debug("TOP response: "+sbResp);
					bw.write(sbResp.toString());
					bw.flush();*/
				}
			else if (line.toUpperCase().startsWith("QUIT")) {
					bw.write("+OK quitting!\r\n");
					log.debug("quiting the thread");
					getSocket().close();
					break;
				}
				else if (line.toUpperCase().startsWith("AUTH")) {
					bw.write("-ERR I have no AUTH imple.. u come anyways!\r\n");
					bw.flush();
					log.debug("AUTH failed. not supported");
				}
				else if (line.toUpperCase().startsWith("CAPA")) {
					bw.write("+OK \r\nUSER\r\nUIDL\r\nTOP\r\n.\r\n");
					bw.flush();
					log.debug("CAPAbilities are made known");
				}

			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		log.exit("thread end");
	}

	public Socket getSocket() {
		return socket;
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	public Message getMessage() {
		return message;
	}

	public void setMessage(Message message) {
		this.message = message;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public StringBuilder getSbRawMsg() {
		return sbRawMsg;
	}

	public void setSbRawMsg(StringBuilder sbRawMsg) {
		this.sbRawMsg = sbRawMsg;
	}

}
